Skip to content

feat: Add phishing-triage kit#182

Open
SharvikS wants to merge 1 commit into
Lamatic:mainfrom
SharvikS:feat/phishing-triage
Open

feat: Add phishing-triage kit#182
SharvikS wants to merge 1 commit into
Lamatic:mainfrom
SharvikS:feat/phishing-triage

Conversation

@SharvikS

@SharvikS SharvikS commented Jul 7, 2026

Copy link
Copy Markdown

PR Checklist

1. Select Contribution Type

  • Kit (kits/<category>/<kit-name>/)
  • Bundle (bundles/<bundle-name>/)
  • Template (templates/<template-name>/)

2. General Requirements

  • PR is for one project only (no unrelated changes)
  • No secrets, API keys, or real credentials are committed
  • Folder name uses kebab-case and matches the flow ID
  • All changes are documented in README.md (purpose, setup, usage)

3. File Structure (Check what applies)

  • config.json present with valid metadata (name, description, tags, steps, author, env keys)
  • All flows in flows/<flow-name>/ (where applicable) include:
    • config.json (Lamatic flow export)
    • inputs.json
    • meta.json
    • README.md
  • .env.example with placeholder values only (kits only)
  • No hand‑edited flow config.json node graphs (changes via Lamatic Studio export)

4. Validation

  • npm install && npm run dev works locally (kits: UI runs; bundles/templates: flows are valid)
  • PR title is clear (e.g., [kit] Add <name> for <use case>)
  • GitHub Actions workflows pass (all checks are green)
  • All CodeRabbit or other PR review comments are addressed and resolved
  • No unrelated files or projects are modified
  • Added a new phishing-triage kit with kit metadata, deployment links, constitution, prompts, model config, and Lamatic flow definitions.
  • Added the core phishing triage flow, which uses:
    • triggerNode for GraphQL/API input
    • a code node to extract IOCs
    • an LLMNode to analyze phishing risk
    • a final code node to normalize the verdict
    • graphqlResponseNode to return the final answer
  • Added a Next.js app for the kit, including app config, TypeScript/PostCSS/Next setup, env templates, and ignore files.
  • Added the phishing triage web UI: home page, orchestration/action helpers, Lamatic client, layout, styling, theme provider, header, and supporting README/docs.
  • Added a broad set of reusable UI primitives and hooks under apps/components/ui and apps/hooks, covering forms, dialogs, menus, tables, charts, navigation, sidebar, toast, and other shared controls used by the app.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

:robot_face: AgentKit Structural Validation

New Contributions Detected

  • Kit: kits/phishing-triage

Check Results

Check Status
No edits to existing kits ✅ Pass
Required root files present ✅ Pass
Flow .ts files present ✅ Pass
lamatic.config.ts valid ✅ Pass
No changes outside kits/ ✅ Pass

🎉 All checks passed! This contribution follows the AgentKit structure.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR introduces a complete "Phishing Email Triage" kit for the Lamatic AgentKit repository: a flow definition, prompts, model config, constitution, and kit metadata for automated email triage, plus a Next.js analyst console web app with a server action calling the flow, a full shadcn/ui component library, styling, and documentation.

Changes

Phishing Triage Kit

Layer / File(s) Summary
Flow, prompts, model config, constitution
kits/phishing-triage/flows/phishing-triage.ts, kits/phishing-triage/lamatic.config.ts, kits/phishing-triage/model-configs/phishing-triage_analyze.ts, kits/phishing-triage/prompts/*, kits/phishing-triage/constitutions/default.md
Defines the trigger → IOC extraction → LLM analysis → verdict finalization → response node graph, system/user prompts, model config placeholder, kit metadata/deploy links, and safety constitution.
Kit documentation and root config
kits/phishing-triage/README.md, kits/phishing-triage/agent.md, kits/phishing-triage/.env.example, kits/phishing-triage/.gitignore
Documents the kit's purpose, verdict schema, setup, guardrails, and limitations; adds root-level env/gitignore placeholders.

Analyst Console Web App

Layer / File(s) Summary
App config and Lamatic client
apps/package.json, apps/tsconfig.json, apps/next.config.mjs, apps/postcss.config.mjs, apps/components.json, apps/orchestrate.ts, apps/lib/lamatic-client.ts, apps/lib/utils.ts, apps/.env.example, apps/.gitignore, apps/.npmrc, apps/README.md
Sets up the Next.js project, environment-driven config, and a validated Lamatic client instance used by server actions.
Server action
apps/actions/orchestrate.ts
Defines EmailInput/Verdict types and analyzeEmail, which calls the Lamatic flow and returns a typed verdict or error.
Page, layout, and styling
apps/app/page.tsx, apps/app/layout.tsx, apps/app/globals.css, apps/components/header.tsx, apps/components/theme-provider.tsx
Implements the analyst console UI: form state, sample loading, verdict rendering, root layout, and design tokens.
Core UI primitives
apps/components/ui/button.tsx, input.tsx, card.tsx, badge.tsx, label.tsx, textarea.tsx, separator.tsx, form.tsx, field.tsx, alert.tsx, progress.tsx, skeleton.tsx, spinner.tsx
Reusable base building-block components used throughout the console.
Overlay/menu UI primitives
apps/components/ui/dialog.tsx, sheet.tsx, drawer.tsx, popover.tsx, dropdown-menu.tsx, menubar.tsx, context-menu.tsx, alert-dialog.tsx, tooltip.tsx, hover-card.tsx, command.tsx, navigation-menu.tsx
Radix-based dialog, menu, and command palette components.
Form control UI primitives
apps/components/ui/select.tsx, checkbox.tsx, radio-group.tsx, switch.tsx, slider.tsx, toggle.tsx, toggle-group.tsx, input-otp.tsx, input-group.tsx, calendar.tsx, pagination.tsx
Interactive form control components for the console.
Layout/data-display UI primitives
apps/components/ui/sidebar.tsx, table.tsx, tabs.tsx, accordion.tsx, avatar.tsx, breadcrumb.tsx, carousel.tsx, chart.tsx, collapsible.tsx, item.tsx, kbd.tsx, empty.tsx, resizable.tsx, scroll-area.tsx, aspect-ratio.tsx, button-group.tsx, hooks/use-mobile.ts
Structural, navigation, and data-display components plus mobile detection hook.
Toast notification system
apps/components/ui/use-toast.ts, toast.tsx, toaster.tsx, sonner.tsx, apps/hooks/use-toast.ts
In-memory toast state management, toast primitives, and toaster/sonner rendering components.

Suggested reviewers: amanintech, d-pamneja

Mission accepted. This message will self-destruct in five seconds—but the phishing triage kit will not: a full flow, prompts, guardrails, and a shadcn-powered console have been dropped, briefcase and all. Your task, should you choose to accept it, is to review a component library large enough to require its own safehouse. Good luck.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is only the checklist template and lacks filled project-specific details or completed validation items. Fill in the checklist with actual kit details, confirm required files and validation results, and remove the placeholder template text.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is clear and matches the main change: adding the phishing-triage kit.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 21

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
kits/phishing-triage/apps/components/ui/use-toast.ts (1)

1-192: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Two agents, one identical playbook — consolidate the toast hook.

This file is an exact duplicate of kits/phishing-triage/apps/hooks/use-toast.ts (same reducer, dispatch, listeners, toast()/useToast()). Having two independent copies of the same in-memory store risks state divergence (e.g., separate memoryState/listeners singletons per module if both are imported by different consumers) and doubles future maintenance.

♻️ Proposed fix

Keep one canonical implementation (e.g., hooks/use-toast.ts) and have the other simply re-export it:

-'use client'
-
-// Inspired by react-hot-toast library
-import * as React from 'react'
-
-... (full duplicated implementation) ...
+export { useToast, toast, reducer } from '`@/hooks/use-toast`'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kits/phishing-triage/apps/components/ui/use-toast.ts` around lines 1 - 192,
The toast hook logic in useToast, reducer, toast, and the module-level
memoryState/listeners store is duplicated and can diverge if both copies are
imported. Consolidate to a single canonical implementation (for example the
existing hooks/use-toast.ts) and make this file re-export that module’s useToast
and toast exports so all consumers share one in-memory store.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@kits/phishing-triage/.env.example`:
- Around line 5-7: The sample env placeholders in the dotenv example need
cleanup for dotenv-linter compliance: remove the unnecessary quotes from the
Lamatic credential values, and reorder the Lamatic entries so LAMATIC_API_KEY
comes before LAMATIC_API_URL while keeping PHISHING_TRIAGE quoted since its
placeholder contains spaces. Update the placeholder entries in the env sample
accordingly so the existing env-variable names remain clear and lint-friendly.

In `@kits/phishing-triage/apps/actions/orchestrate.ts`:
- Around line 47-55: The parsed flow response in orchestrate.ts is being cast to
Verdict without runtime shape checking, so malformed or partial payloads can
reach the UI. Add schema validation in the orchestrate flow after JSON.parse and
before returning success, using the Verdict contract from orchestrate.ts (or a
shared zod schema) to verify required fields like indicators, extracted_urls,
and verdict. If validation fails, throw a clear error instead of returning data
so page.tsx never receives an invalid verdict object.
- Line 44: The executeFlow call in orchestrate should be protected by an
application-level timeout because it can otherwise hang the server action;
update the flow execution path around lamaticClient.executeFlow in orchestrate
to enforce a hard timeout and fail fast when exceeded. If cancellation is
needed, route the request through a lower-level client path that supports
aborting, and keep the timeout handling localized to the flow call so the rest
of the action can recover cleanly.

In `@kits/phishing-triage/apps/app/layout.tsx`:
- Around line 6-7: The next/font instances in layout are created but never used,
so the optimized Geist fonts never reach the page. Update the App Router layout
component to apply the appropriate `variable` or `className` from `Geist` and
`Geist_Mono` on the `<html>` or `<body>` element, and adjust `globals.css` so
`--font-sans` references the next/font CSS variable instead of the literal Geist
family name. Use the `Geist`, `Geist_Mono`, and root layout markup to locate the
fix.
- Around line 15-26: RootLayout is missing the next-themes provider, so theme
state never reaches consumers like the Sonner toaster and the dark class won’t
be applied. Update RootLayout to wrap the rendered app in ThemeProvider, and add
suppressHydrationWarning to the html element; use the existing RootLayout
component in app/layout.tsx and keep Analytics inside the provider tree.

In `@kits/phishing-triage/apps/app/page.tsx`:
- Around line 58-66: The loading state in onAnalyze can get stuck if
analyzeEmail throws before reaching the final setLoading(false). Update the
onAnalyze handler in the page component to wrap the analyzeEmail call in a
try/finally block so loading is always cleared, while keeping the existing
success/error handling for the result and error state.
- Around line 34-38: The VERDICT_STYLES mapping uses a loose any type for the
icon field, which should be replaced with the correct Lucide icon component
type. Update the type annotation on VERDICT_STYLES in page.tsx to use a proper
icon component type that matches AlertTriangle, ShieldQuestion, and
CheckCircle2, so the contract stays explicit and type-safe without changing the
mapping values.

In `@kits/phishing-triage/apps/components/ui/carousel.tsx`:
- Around line 96-105: The cleanup in the Carousel effect is only unsubscribing
the `select` listener, leaving the `reInit` listener registered and causing
stale `onSelect` handlers to accumulate. Update the `React.useEffect` tied to
`api` and `onSelect` so the returned cleanup removes every listener added in the
effect, including both `api.on('reInit', onSelect)` and `api.on('select',
onSelect)`. Keep the subscription and unsubscription logic paired in the same
`useEffect` block to ensure Embla listeners are fully torn down on re-render or
unmount.

In `@kits/phishing-triage/apps/components/ui/chart.tsx`:
- Around line 72-103: The ChartStyle component is interpolating unvalidated
ChartConfig color/theme values directly into a raw style tag via
dangerouslySetInnerHTML, which creates an injection risk. Update ChartStyle to
validate or sanitize the resolved color before it is inserted into the CSS
string, and only emit safe CSS values from the config/theme lookup. Use the
existing ChartStyle, colorConfig, and THEMES flow to locate the fix, and keep
the dynamic style generation while ensuring any value coming from config cannot
break out of the CSS declaration.

In `@kits/phishing-triage/apps/components/ui/empty.tsx`:
- Around line 71-82: EmptyDescription is typed as React.ComponentProps<'p'> but
renders a div, so update the component to use the paragraph element
consistently. Keep the existing className/cn styling and props forwarding, but
change the rendered element inside EmptyDescription to match the p-based props
and semantics so consumers using EmptyDescription get the expected runtime
element.

In `@kits/phishing-triage/apps/components/ui/input-group.tsx`:
- Around line 1-9: The input-group component references React.ComponentProps in
several type definitions but never imports React, so add the React import at the
top of the file alongside the existing imports. Update the input-group.tsx
module that defines the input group, input, button, and addon component types so
the React namespace is available wherever ComponentProps is used.

In `@kits/phishing-triage/apps/components/ui/kbd.tsx`:
- Around line 18-26: KbdGroup currently declares div props but renders a kbd
element, so update the KbdGroup component to render a div instead and keep its
React.ComponentProps<'div'> contract aligned; preserve the existing data-slot,
className, and props passthrough behavior while changing only the outer element
in KbdGroup.

In `@kits/phishing-triage/apps/components/ui/sonner.tsx`:
- Around line 3-19: The Toaster component in sonner.tsx casts the inline style
to React.CSSProperties without importing React, so TypeScript cannot resolve
that namespace. Update the imports at the top of Toaster/Sonner component file
by adding a React import, or switch the cast to a directly imported
CSSProperties type, while keeping the existing Toaster and useTheme logic
unchanged.

In `@kits/phishing-triage/apps/components/ui/toaster.tsx`:
- Around line 1-35: The app currently has two separate toast implementations
exposing the same Toaster component name, which can cause duplicate
notifications or one to silently override the other. Consolidate on a single
toast system by choosing either the Radix-based Toaster here or the Sonner-based
one in sonner.tsx, then remove or rename the unused implementation and update
any layout or provider wiring so only one toast stack is mounted.

In `@kits/phishing-triage/apps/components/ui/use-mobile.tsx`:
- Around line 1-19: The useIsMobile hook is duplicated here and in the shared
hooks module, so keep only one source of truth to avoid divergence. Update the
ui/use-mobile.tsx module to re-export the existing useIsMobile implementation
from the shared hooks/use-mobile module, or remove this duplicate copy entirely,
and ensure sidebar.tsx continues using the shared hook reference.

In `@kits/phishing-triage/apps/components/ui/use-toast.ts`:
- Around line 171-182: The subscription in useToast is being torn down and
recreated on every toast update because the effect depends on state even though
only the stable setState callback is needed. Update the React.useEffect in
useToast to subscribe once on mount and unsubscribe on unmount by using an empty
dependency array (or otherwise removing state from the dependencies), while
keeping the listeners.push/remove logic intact.
- Around line 8-9: The toast cleanup delay in use-toast.ts is far too long,
causing dismissed toasts to remain in state for an excessive time. Update
TOAST_REMOVE_DELAY to a much shorter removal delay that matches the intended UX,
and keep the change localized to the toast state management around TOAST_LIMIT
and TOAST_REMOVE_DELAY so dismissed items are actually cleared promptly.

In `@kits/phishing-triage/apps/next.config.mjs`:
- Around line 8-10: Remove the TypeScript build override in the Next.js config
so build-time type errors are no longer ignored. Update the next.config.mjs
configuration around the typescript block to stop setting ignoreBuildErrors to
true, and ensure the app is cleaned up until next build succeeds with type
checking enabled.

In `@kits/phishing-triage/apps/orchestrate.ts`:
- Around line 10-12: Normalize the fallback values in AppConfig construction so
the config shape is consistent across endpoint, projectId, and apiKey. Update
the orchestration setup in orchestrate.ts where the config object is built so
all env-derived fields use the same null/empty-string convention, and keep the
AppConfig type aligned with that choice to avoid mixed defaults.

In `@kits/phishing-triage/apps/package.json`:
- Line 53: The package manifest currently uses a floating version for lamatic,
which makes installs non-reproducible. Update the dependencies in the
package.json for lamatic (and react-markdown as noted in the review) to fixed,
pinned versions instead of latest so fresh installs always resolve to the same
package versions.

In `@kits/phishing-triage/README.md`:
- Around line 1-5: The deploy anchor in the phishing-triage README opens a new
tab but is missing the required rel attributes, creating a tab-nabbing risk.
Update the external link that uses target="_blank" to include rel="noopener
noreferrer" so the Vercel deploy button remains safe when opened from the
README.

---

Outside diff comments:
In `@kits/phishing-triage/apps/components/ui/use-toast.ts`:
- Around line 1-192: The toast hook logic in useToast, reducer, toast, and the
module-level memoryState/listeners store is duplicated and can diverge if both
copies are imported. Consolidate to a single canonical implementation (for
example the existing hooks/use-toast.ts) and make this file re-export that
module’s useToast and toast exports so all consumers share one in-memory store.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7d0fcc46-818b-43fb-9d37-80d0debcc37c

📥 Commits

Reviewing files that changed from the base of the PR and between dafde4c and a7590f2.

📒 Files selected for processing (87)
  • kits/phishing-triage/.env.example
  • kits/phishing-triage/.gitignore
  • kits/phishing-triage/README.md
  • kits/phishing-triage/agent.md
  • kits/phishing-triage/apps/.env.example
  • kits/phishing-triage/apps/.gitignore
  • kits/phishing-triage/apps/.npmrc
  • kits/phishing-triage/apps/README.md
  • kits/phishing-triage/apps/actions/orchestrate.ts
  • kits/phishing-triage/apps/app/globals.css
  • kits/phishing-triage/apps/app/layout.tsx
  • kits/phishing-triage/apps/app/page.tsx
  • kits/phishing-triage/apps/components.json
  • kits/phishing-triage/apps/components/header.tsx
  • kits/phishing-triage/apps/components/theme-provider.tsx
  • kits/phishing-triage/apps/components/ui/accordion.tsx
  • kits/phishing-triage/apps/components/ui/alert-dialog.tsx
  • kits/phishing-triage/apps/components/ui/alert.tsx
  • kits/phishing-triage/apps/components/ui/aspect-ratio.tsx
  • kits/phishing-triage/apps/components/ui/avatar.tsx
  • kits/phishing-triage/apps/components/ui/badge.tsx
  • kits/phishing-triage/apps/components/ui/breadcrumb.tsx
  • kits/phishing-triage/apps/components/ui/button-group.tsx
  • kits/phishing-triage/apps/components/ui/button.tsx
  • kits/phishing-triage/apps/components/ui/calendar.tsx
  • kits/phishing-triage/apps/components/ui/card.tsx
  • kits/phishing-triage/apps/components/ui/carousel.tsx
  • kits/phishing-triage/apps/components/ui/chart.tsx
  • kits/phishing-triage/apps/components/ui/checkbox.tsx
  • kits/phishing-triage/apps/components/ui/collapsible.tsx
  • kits/phishing-triage/apps/components/ui/command.tsx
  • kits/phishing-triage/apps/components/ui/context-menu.tsx
  • kits/phishing-triage/apps/components/ui/dialog.tsx
  • kits/phishing-triage/apps/components/ui/drawer.tsx
  • kits/phishing-triage/apps/components/ui/dropdown-menu.tsx
  • kits/phishing-triage/apps/components/ui/empty.tsx
  • kits/phishing-triage/apps/components/ui/field.tsx
  • kits/phishing-triage/apps/components/ui/form.tsx
  • kits/phishing-triage/apps/components/ui/hover-card.tsx
  • kits/phishing-triage/apps/components/ui/input-group.tsx
  • kits/phishing-triage/apps/components/ui/input-otp.tsx
  • kits/phishing-triage/apps/components/ui/input.tsx
  • kits/phishing-triage/apps/components/ui/item.tsx
  • kits/phishing-triage/apps/components/ui/kbd.tsx
  • kits/phishing-triage/apps/components/ui/label.tsx
  • kits/phishing-triage/apps/components/ui/menubar.tsx
  • kits/phishing-triage/apps/components/ui/navigation-menu.tsx
  • kits/phishing-triage/apps/components/ui/pagination.tsx
  • kits/phishing-triage/apps/components/ui/popover.tsx
  • kits/phishing-triage/apps/components/ui/progress.tsx
  • kits/phishing-triage/apps/components/ui/radio-group.tsx
  • kits/phishing-triage/apps/components/ui/resizable.tsx
  • kits/phishing-triage/apps/components/ui/scroll-area.tsx
  • kits/phishing-triage/apps/components/ui/select.tsx
  • kits/phishing-triage/apps/components/ui/separator.tsx
  • kits/phishing-triage/apps/components/ui/sheet.tsx
  • kits/phishing-triage/apps/components/ui/sidebar.tsx
  • kits/phishing-triage/apps/components/ui/skeleton.tsx
  • kits/phishing-triage/apps/components/ui/slider.tsx
  • kits/phishing-triage/apps/components/ui/sonner.tsx
  • kits/phishing-triage/apps/components/ui/spinner.tsx
  • kits/phishing-triage/apps/components/ui/switch.tsx
  • kits/phishing-triage/apps/components/ui/table.tsx
  • kits/phishing-triage/apps/components/ui/tabs.tsx
  • kits/phishing-triage/apps/components/ui/textarea.tsx
  • kits/phishing-triage/apps/components/ui/toast.tsx
  • kits/phishing-triage/apps/components/ui/toaster.tsx
  • kits/phishing-triage/apps/components/ui/toggle-group.tsx
  • kits/phishing-triage/apps/components/ui/toggle.tsx
  • kits/phishing-triage/apps/components/ui/tooltip.tsx
  • kits/phishing-triage/apps/components/ui/use-mobile.tsx
  • kits/phishing-triage/apps/components/ui/use-toast.ts
  • kits/phishing-triage/apps/hooks/use-mobile.ts
  • kits/phishing-triage/apps/hooks/use-toast.ts
  • kits/phishing-triage/apps/lib/lamatic-client.ts
  • kits/phishing-triage/apps/lib/utils.ts
  • kits/phishing-triage/apps/next.config.mjs
  • kits/phishing-triage/apps/orchestrate.ts
  • kits/phishing-triage/apps/package.json
  • kits/phishing-triage/apps/postcss.config.mjs
  • kits/phishing-triage/apps/tsconfig.json
  • kits/phishing-triage/constitutions/default.md
  • kits/phishing-triage/flows/phishing-triage.ts
  • kits/phishing-triage/lamatic.config.ts
  • kits/phishing-triage/model-configs/phishing-triage_analyze.ts
  • kits/phishing-triage/prompts/phishing-triage_analyze_system.md
  • kits/phishing-triage/prompts/phishing-triage_analyze_user.md

Comment on lines +5 to +7
LAMATIC_API_URL="LAMATIC_API_URL"
LAMATIC_PROJECT_ID="LAMATIC_PROJECT_ID"
LAMATIC_API_KEY="LAMATIC_API_KEY"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Clean up the sample env values for dotenv-linter.

The Lamatic credential placeholders do not need quotes, and LAMATIC_API_KEY should come before LAMATIC_API_URL if the repo keeps enforcing dotenv-linter. PHISHING_TRIAGE can stay quoted because its placeholder contains spaces.

♻️ Proposed fix
 # Phishing Triage flow ID (from Lamatic Studio → your deployed flow)
 PHISHING_TRIAGE="PHISHING_TRIAGE Flow ID"

 # Lamatic project credentials (Studio → Settings)
-LAMATIC_API_URL="LAMATIC_API_URL"
-LAMATIC_PROJECT_ID="LAMATIC_PROJECT_ID"
-LAMATIC_API_KEY="LAMATIC_API_KEY"
+LAMATIC_API_KEY=LAMATIC_API_KEY
+LAMATIC_API_URL=LAMATIC_API_URL
+LAMATIC_PROJECT_ID=LAMATIC_PROJECT_ID
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
LAMATIC_API_URL="LAMATIC_API_URL"
LAMATIC_PROJECT_ID="LAMATIC_PROJECT_ID"
LAMATIC_API_KEY="LAMATIC_API_KEY"
LAMATIC_API_KEY=LAMATIC_API_KEY
LAMATIC_API_URL=LAMATIC_API_URL
LAMATIC_PROJECT_ID=LAMATIC_PROJECT_ID
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 5-5: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 6-6: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 7-7: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 7-7: [UnorderedKey] The LAMATIC_API_KEY key should go before the LAMATIC_API_URL key

(UnorderedKey)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kits/phishing-triage/.env.example` around lines 5 - 7, The sample env
placeholders in the dotenv example need cleanup for dotenv-linter compliance:
remove the unnecessary quotes from the Lamatic credential values, and reorder
the Lamatic entries so LAMATIC_API_KEY comes before LAMATIC_API_URL while
keeping PHISHING_TRIAGE quoted since its placeholder contains spaces. Update the
placeholder entries in the env sample accordingly so the existing env-variable
names remain clear and lint-friendly.

Source: Linters/SAST tools

body: email.body,
}

const resData: any = await lamaticClient.executeFlow(flow.workflowId, inputs)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '== orchestrate file ==\n'
cat -n kits/phishing-triage/apps/actions/orchestrate.ts | sed -n '1,220p'

printf '\n== search for lamaticClient / executeFlow ==\n'
rg -n "executeFlow|lamaticClient|lamatic" kits/phishing-triage/apps -S

printf '\n== search repository for SDK types/docs ==\n'
rg -n "executeFlow\\(" -S .
rg -n "AbortController|signal|timeout" -S kits/phishing-triage/apps .

Repository: Lamatic/AgentKit

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '== phishing-triage lamatic client ==\n'
cat -n kits/phishing-triage/apps/lib/lamatic-client.ts | sed -n '1,220p'

printf '\n== weekly-routine-coach timeout wrapper reference ==\n'
cat -n kits/weekly-routine-coach/apps/lib/lamatic-client.ts | sed -n '1,180p'

printf '\n== lamatic package version pins ==\n'
rg -n '"lamatic"|lamatic@' kits/*/apps/package.json kits/*/apps/package-lock.json kits/*/apps/pnpm-lock.yaml -S

printf '\n== search for executeFlow type declarations in repo ==\n'
rg -n "executeFlow\\s*\\(" kits -g '!**/node_modules/**' -S

Repository: Lamatic/AgentKit

Length of output: 14219


🌐 Web query:

Lamatic SDK executeFlow AbortController signal timeout options lamatic package documentation

💡 Result:

The official Lamatic SDK documentation for executeFlow does not natively support AbortController or specific timeout signal options directly within the method signature [1][2][3][4]. The executeFlow(flowId: string, payload: Object) method signature is designed to execute a workflow and return a promise [1][2]. It does not accept additional configuration objects for request cancellation or timeout control [2]. If you need to implement timeouts or cancellation, you must handle these patterns at the application level rather than through the SDK method arguments: 1. Request Timeouts: Because the SDK does not provide a signal parameter, you can manage timeouts by wrapping the executeFlow call in a promise race or by implementing custom polling logic [1]. The SDK documentation suggests that for longer-running workflows, you may need to use status-checking methods (like checkStatus) rather than relying on the initial executeFlow promise to resolve within a specific window [1]. 2. AbortController: Since executeFlow does not accept an AbortSignal, it cannot be natively cancelled using the standard Web API AbortController [2]. If your environment allows it, you might be able to implement cancellation by using a lower-level HTTP client (like axios or fetch) directly to send the GraphQL request, which would allow you to pass an AbortSignal to the underlying request [5][6]. For best practices, always wrap executeFlow in try-catch blocks, as the SDK throws exceptions for configuration, network, or parsing issues [1][2]. If you encounter a timeout, the documentation notes that the request may still be executing in the background, and you should check the status again using the request ID [1].

Citations:


Bound this flow call with an application-level timeout. lamaticClient.executeFlow doesn’t accept AbortSignal/timeout options, so a slow or hung flow can still stall this server action. Wrap it with a timeout guard, or switch to a lower-level request path if cancellation is required.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kits/phishing-triage/apps/actions/orchestrate.ts` at line 44, The executeFlow
call in orchestrate should be protected by an application-level timeout because
it can otherwise hang the server action; update the flow execution path around
lamaticClient.executeFlow in orchestrate to enforce a hard timeout and fail fast
when exceeded. If cancellation is needed, route the request through a
lower-level client path that supports aborting, and keep the timeout handling
localized to the flow call so the rest of the action can recover cleanly.

Comment on lines +47 to +55
const answer = resData?.result?.answer ?? resData?.result?.output ?? resData?.answer

if (!answer) {
throw new Error("No verdict was returned by the flow.")
}

const parsed: Verdict = typeof answer === "string" ? JSON.parse(answer) : answer

return { success: true, data: parsed }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Verdict is trusted blind — no schema validation before it ships to the UI.

Verdict declares indicators, extracted_urls, verdict, etc. as required, non-optional fields, but the parsed answer (LLM/flow output, possibly a raw JSON string) is cast to Verdict with zero runtime validation. Confirmed by the downstream consumer (kits/phishing-triage/apps/app/page.tsx) defensively using result.indicators?.length > 0 and result.extracted_urls?.length > 0 — optional chaining on fields the type promises are always present. If the flow returns a malformed/partial payload, JSON.parse succeeds but the shape mismatch surfaces as silent UI breakage (e.g. VERDICT_STYLES[result.verdict] returning undefined for an unexpected verdict string) rather than a clear error to the analyst.

🛡️ Proposed fix: validate with zod before returning success
+const VerdictSchema = z.object({
+  verdict: z.enum(["phishing", "suspicious", "legitimate"]),
+  confidence: z.number(),
+  risk_score: z.number(),
+  indicators: z.array(z.string()),
+  extracted_urls: z.array(z.string()),
+  recommended_action: z.string(),
+  reasoning: z.string(),
+  iocs: z.record(z.unknown()).optional(),
+})
+
-    const parsed: Verdict = typeof answer === "string" ? JSON.parse(answer) : answer
+    const rawParsed = typeof answer === "string" ? JSON.parse(answer) : answer
+    const parsed: Verdict = VerdictSchema.parse(rawParsed)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const answer = resData?.result?.answer ?? resData?.result?.output ?? resData?.answer
if (!answer) {
throw new Error("No verdict was returned by the flow.")
}
const parsed: Verdict = typeof answer === "string" ? JSON.parse(answer) : answer
return { success: true, data: parsed }
const VerdictSchema = z.object({
verdict: z.enum(["phishing", "suspicious", "legitimate"]),
confidence: z.number(),
risk_score: z.number(),
indicators: z.array(z.string()),
extracted_urls: z.array(z.string()),
recommended_action: z.string(),
reasoning: z.string(),
iocs: z.record(z.unknown()).optional(),
})
const answer = resData?.result?.answer ?? resData?.result?.output ?? resData?.answer
if (!answer) {
throw new Error("No verdict was returned by the flow.")
}
const rawParsed = typeof answer === "string" ? JSON.parse(answer) : answer
const parsed: Verdict = VerdictSchema.parse(rawParsed)
return { success: true, data: parsed }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kits/phishing-triage/apps/actions/orchestrate.ts` around lines 47 - 55, The
parsed flow response in orchestrate.ts is being cast to Verdict without runtime
shape checking, so malformed or partial payloads can reach the UI. Add schema
validation in the orchestrate flow after JSON.parse and before returning
success, using the Verdict contract from orchestrate.ts (or a shared zod schema)
to verify required fields like indicators, extracted_urls, and verdict. If
validation fails, throw a clear error instead of returning data so page.tsx
never receives an invalid verdict object.

Comment on lines +6 to +7
const _geist = Geist({ subsets: ["latin"] })
const _geistMono = Geist_Mono({ subsets: ["latin"] })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Font agents never actually deployed to the field.

Geist/Geist_Mono (Line 6-7) are instantiated but their .variable/.className output is never applied to <html> or <body> (Line 20 just uses the static font-sans utility). Since globals.css hardcodes --font-sans: 'Geist', 'Geist Fallback' as a literal family name rather than referencing the next/font CSS variable, the optimized/self-hosted font never loads — you get whatever generic font the browser resolves for the literal string "Geist" (likely nothing, falling to system sans).

🔤 Suggested fix
-const _geist = Geist({ subsets: ["latin"] })
-const _geistMono = Geist_Mono({ subsets: ["latin"] })
+const geist = Geist({ subsets: ["latin"], variable: "--font-geist-sans" })
+const geistMono = Geist_Mono({ subsets: ["latin"], variable: "--font-geist-mono" })
...
-      <body className="font-sans antialiased">
+      <body className={`${geist.variable} ${geistMono.variable} font-sans antialiased`}>

And update globals.css to reference var(--font-geist-sans) instead of the literal 'Geist' family name.

Also applies to: 20-20

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kits/phishing-triage/apps/app/layout.tsx` around lines 6 - 7, The next/font
instances in layout are created but never used, so the optimized Geist fonts
never reach the page. Update the App Router layout component to apply the
appropriate `variable` or `className` from `Geist` and `Geist_Mono` on the
`<html>` or `<body>` element, and adjust `globals.css` so `--font-sans`
references the next/font CSS variable instead of the literal Geist family name.
Use the `Geist`, `Geist_Mono`, and root layout markup to locate the fix.

Comment on lines +15 to +26
export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en">
<body className="font-sans antialiased">
{children}
<Analytics />
</body>
</html>
)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== layout ==\n'
cat -n kits/phishing-triage/apps/app/layout.tsx

printf '\n== theme-provider ==\n'
cat -n kits/phishing-triage/apps/components/theme-provider.tsx

printf '\n== globals.css (first 260 lines) ==\n'
sed -n '1,260p' kits/phishing-triage/apps/app/globals.css

printf '\n== search theme-provider / next-themes usage ==\n'
rg -n "ThemeProvider|next-themes|suppressHydrationWarning|class=\"dark\"|attribute=\"class\"" kits/phishing-triage/apps -g '!**/node_modules/**'

Repository: Lamatic/AgentKit

Length of output: 6476


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== search for theme controls/usages ==\n'
rg -n "setTheme\(|useTheme\(|ThemeProvider|next-themes|dark mode|toggle theme|theme=" kits/phishing-triage/apps -g '!**/node_modules/**'

printf '\n== sonner ==\n'
cat -n kits/phishing-triage/apps/components/ui/sonner.tsx

Repository: Lamatic/AgentKit

Length of output: 1699


Mount ThemeProvider in RootLayout. next-themes is installed, but the app never renders its provider, so the .dark class never gets applied and theme consumers like the Sonner toaster stay disconnected. Wrap the layout in ThemeProvider and add suppressHydrationWarning to <html>.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kits/phishing-triage/apps/app/layout.tsx` around lines 15 - 26, RootLayout is
missing the next-themes provider, so theme state never reaches consumers like
the Sonner toaster and the dark class won’t be applied. Update RootLayout to
wrap the rendered app in ThemeProvider, and add suppressHydrationWarning to the
html element; use the existing RootLayout component in app/layout.tsx and keep
Analytics inside the provider tree.

Comment on lines +171 to +182
function useToast() {
const [state, setState] = React.useState<State>(memoryState)

React.useEffect(() => {
listeners.push(setState)
return () => {
const index = listeners.indexOf(setState)
if (index > -1) {
listeners.splice(index, 1)
}
}
}, [state])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Self-destructing subscription, again and again.

The effect's dependency array [state] re-runs the subscribe/unsubscribe cleanup on every toast dispatch (since state changes each time), even though setState is a stable identity. This churns the shared listeners array unnecessarily on every state update.

♻️ Proposed fix
   React.useEffect(() => {
     listeners.push(setState)
     return () => {
       const index = listeners.indexOf(setState)
       if (index > -1) {
         listeners.splice(index, 1)
       }
     }
-  }, [state])
+  }, [])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function useToast() {
const [state, setState] = React.useState<State>(memoryState)
React.useEffect(() => {
listeners.push(setState)
return () => {
const index = listeners.indexOf(setState)
if (index > -1) {
listeners.splice(index, 1)
}
}
}, [state])
function useToast() {
const [state, setState] = React.useState<State>(memoryState)
React.useEffect(() => {
listeners.push(setState)
return () => {
const index = listeners.indexOf(setState)
if (index > -1) {
listeners.splice(index, 1)
}
}
}, [])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kits/phishing-triage/apps/components/ui/use-toast.ts` around lines 171 - 182,
The subscription in useToast is being torn down and recreated on every toast
update because the effect depends on state even though only the stable setState
callback is needed. Update the React.useEffect in useToast to subscribe once on
mount and unsubscribe on unmount by using an empty dependency array (or
otherwise removing state from the dependencies), while keeping the
listeners.push/remove logic intact.

Comment on lines +8 to +10
typescript: {
ignoreBuildErrors: true,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Your mission, should you choose to accept it: stop ignoring TypeScript build errors.

ignoreBuildErrors: true lets type errors silently ship to production in a tool used to triage phishing threats — exactly the kind of console where a subtle bug shouldn't slip past the compiler. Recommend removing this once the app's type errors (if any) are resolved, so next build fails loudly instead of quietly.

🕵️ Proposed fix
 const nextConfig = {
-  typescript: {
-    ignoreBuildErrors: true,
-  },
   images: {
     unoptimized: true,
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
typescript: {
ignoreBuildErrors: true,
},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kits/phishing-triage/apps/next.config.mjs` around lines 8 - 10, Remove the
TypeScript build override in the Next.js config so build-time type errors are no
longer ignored. Update the next.config.mjs configuration around the typescript
block to stop setting ignoreBuildErrors to true, and ensure the app is cleaned
up until next build succeeds with type checking enabled.

Comment on lines +10 to +12
endpoint: process.env.LAMATIC_API_URL ?? "",
projectId: process.env.LAMATIC_PROJECT_ID ?? null,
apiKey: process.env.LAMATIC_API_KEY ?? "",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Inconsistent env-var fallback defaults.

endpoint/apiKey default to "" while projectId defaults to null — a minor type inconsistency in AppConfig. Low impact since lamatic-client.ts validates directly against process.env, but worth normalizing for consistency.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kits/phishing-triage/apps/orchestrate.ts` around lines 10 - 12, Normalize the
fallback values in AppConfig construction so the config shape is consistent
across endpoint, projectId, and apiKey. Update the orchestration setup in
orchestrate.ts where the config object is built so all env-derived fields use
the same null/empty-string convention, and keep the AppConfig type aligned with
that choice to avoid mixed defaults.

"date-fns": "4.1.0",
"embla-carousel-react": "8.5.1",
"input-otp": "1.4.1",
"lamatic": "latest",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What is the latest published version of the npm package "lamatic"?

💡 Result:

The latest version of the npm package lamatic is not explicitly stated in the provided search results. While official documentation and the associated GitHub repository confirm the existence of the lamatic package and provide instructions for its installation via npm install lamatic [1][2][3], these sources do not display the specific version number. Users can determine the current latest version by running the following command in their terminal: npm view lamatic version

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant package manifest and surrounding context.
sed -n '1,140p' kits/phishing-triage/apps/package.json | cat -n

Repository: Lamatic/AgentKit

Length of output: 3164


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check whether the manifest still uses "latest" for the flagged dependencies.
python3 - <<'PY'
import json
from pathlib import Path

path = Path("kits/phishing-triage/apps/package.json")
data = json.loads(path.read_text())
deps = data.get("dependencies", {})
for name in ["lamatic", "react-markdown"]:
    print(f"{name}: {deps.get(name)!r}")
PY

Repository: Lamatic/AgentKit

Length of output: 197


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find any references to the kit-only layout requirements in the repo for context.
rg -n "apps/package.json|next.config.mjs|tsconfig.json|\.env\.example|kits/" -S .

Repository: Lamatic/AgentKit

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check for lockfiles in the kit app directory and inspect the app metadata.
fd -a 'package-lock.json|pnpm-lock.yaml|yarn.lock' kits/phishing-triage/apps kits/phishing-triage -t f

Repository: Lamatic/AgentKit

Length of output: 154


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
for p in [
    Path("kits/phishing-triage/apps/package-lock.json"),
    Path("kits/phishing-triage/apps/pnpm-lock.yaml"),
    Path("kits/phishing-triage/apps/yarn.lock"),
    Path("kits/phishing-triage/package-lock.json"),
]:
    print(f"{p}: {'exists' if p.exists() else 'missing'}")
PY

Repository: Lamatic/AgentKit

Length of output: 350


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect whether the kit app ships a lockfile near package.json.
find kits/phishing-triage -maxdepth 2 \( -name 'package-lock.json' -o -name 'pnpm-lock.yaml' -o -name 'yarn.lock' \) -print

Repository: Lamatic/AgentKit

Length of output: 154


Pin these dependencies instead of latest
lamatic and react-markdown will float to whatever npm publishes next. With no lockfile in this kit, fresh installs can pull breaking changes and make builds non-reproducible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kits/phishing-triage/apps/package.json` at line 53, The package manifest
currently uses a floating version for lamatic, which makes installs
non-reproducible. Update the dependencies in the package.json for lamatic (and
react-markdown as noted in the review) to fixed, pinned versions instead of
latest so fresh installs always resolve to the same package versions.

Comment on lines +1 to +5
<a href="https://vercel.com/new/clone?repository-url=https://github.com/Lamatic/AgentKit&root-directory=kits%2Fphishing-triage%2Fapps&env=PHISHING_TRIAGE,LAMATIC_API_URL,LAMATIC_PROJECT_ID,LAMATIC_API_KEY" target="_blank" style="text-decoration:none;">
<div align="right">
<span style="display:inline-block;background:#e63946;color:#fff;border-radius:6px;padding:10px 22px;font-size:16px;font-weight:bold;letter-spacing:0.5px;text-align:center;box-shadow:0 2px 8px 0 #0001;">Deploy on Vercel</span>
</div>
</a>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Add rel="noopener noreferrer" to the deploy link.

Opening an external page in a new tab without it leaves a tab-nabbing surface.

🔧 Suggested fix
-<a href="https://vercel.com/new/clone?repository-url=https://github.com/Lamatic/AgentKit&root-directory=kits%2Fphishing-triage%2Fapps&env=PHISHING_TRIAGE,LAMATIC_API_URL,LAMATIC_PROJECT_ID,LAMATIC_API_KEY" target="_blank" style="text-decoration:none;">
+<a href="https://vercel.com/new/clone?repository-url=https://github.com/Lamatic/AgentKit&root-directory=kits%2Fphishing-triage%2Fapps&env=PHISHING_TRIAGE,LAMATIC_API_URL,LAMATIC_PROJECT_ID,LAMATIC_API_KEY" target="_blank" rel="noopener noreferrer" style="text-decoration:none;">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<a href="https://vercel.com/new/clone?repository-url=https://github.com/Lamatic/AgentKit&root-directory=kits%2Fphishing-triage%2Fapps&env=PHISHING_TRIAGE,LAMATIC_API_URL,LAMATIC_PROJECT_ID,LAMATIC_API_KEY" target="_blank" style="text-decoration:none;">
<div align="right">
<span style="display:inline-block;background:#e63946;color:#fff;border-radius:6px;padding:10px 22px;font-size:16px;font-weight:bold;letter-spacing:0.5px;text-align:center;box-shadow:0 2px 8px 0 #0001;">Deploy on Vercel</span>
</div>
</a>
<a href="https://vercel.com/new/clone?repository-url=https://github.com/Lamatic/AgentKit&root-directory=kits%2Fphishing-triage%2Fapps&env=PHISHING_TRIAGE,LAMATIC_API_URL,LAMATIC_PROJECT_ID,LAMATIC_API_KEY" target="_blank" rel="noopener noreferrer" style="text-decoration:none;">
<div align="right">
<span style="display:inline-block;background:`#e63946`;color:`#fff`;border-radius:6px;padding:10px 22px;font-size:16px;font-weight:bold;letter-spacing:0.5px;text-align:center;box-shadow:0 2px 8px 0 `#0001`;">Deploy on Vercel</span>
</div>
</a>
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@kits/phishing-triage/README.md` around lines 1 - 5, The deploy anchor in the
phishing-triage README opens a new tab but is missing the required rel
attributes, creating a tab-nabbing risk. Update the external link that uses
target="_blank" to include rel="noopener noreferrer" so the Vercel deploy button
remains safe when opened from the README.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Hi @SharvikS! 👋

Before this PR can be reviewed by maintainers, please resolve all comments and requested changes from the CodeRabbit automated review.

Steps to follow:

  1. Read through all CodeRabbit comments carefully
  2. Address each issue raised (or reply explaining why you disagree)
  3. Push your fixes as new commits
  4. Once all issues are resolved, comment here so we can re-review

This helps keep the review process efficient for everyone. Thank you! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant